package com.ruoyi.system.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.DataType;
import com.ruoyi.system.domain.Device;
import com.ruoyi.system.domain.DeviceTerminal;
import com.ruoyi.system.domain.Product;
import com.ruoyi.system.domain.ProductTelemetry;
import com.ruoyi.system.domain.ProjectScenarioAction;
import com.ruoyi.system.domain.SysCompanyThingsboard;
import com.ruoyi.system.domain.vo.QueryVo;
import com.ruoyi.system.service.IDeviceService;
import com.ruoyi.system.service.IProductTelemetryService;
import com.ruoyi.system.service.IProjectScenarioActionService;
import com.ruoyi.system.service.ISpecificFunctionService;
import com.ruoyi.system.service.ISysCompanyThingsboardService;
import com.ruoyi.system.service.IThingsBoardTenantService;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class SpecificFunctionServiceImpl implements ISpecificFunctionService {
    @Autowired
    IProjectScenarioActionService projectScenarioActionService;

    @Autowired
    ISysCompanyThingsboardService sysCompanyThingsboardService;

    @Autowired
    IDeviceService deviceService;

    @Autowired
    IProductTelemetryService productTelemetryService;

    @Autowired
    IThingsBoardTenantService thingsBoardTenantService;

    private String getPayloadDigest(JSONObject data, JSONObject params, String token) {
        String digest = null;
        List<String> pieces = new ArrayList<>();
        List<String> dataKeys = new ArrayList<>(data.keySet());
        Collections.sort(dataKeys);
        for (String dataKey: dataKeys) {
            String value = data.get(dataKey).toString();
            pieces.add(String.format("%s=%s", dataKey, value));
        }
        List<String> paramKeys = new ArrayList<>(params.keySet());
        Collections.sort(paramKeys);
        for (String parameterKey: paramKeys) {
            String value = params.get(parameterKey).toString();
            pieces.add(String.format("%s=%s", parameterKey, value));
        }
        pieces.add(String.format("token=%s", token));
        String raw = String.join("&", pieces);
        digest = DigestUtils.sha1Hex(raw);
        return digest;
    }

    @Override
    public AjaxResult productTelemetryIncrement(JSONObject request) {
        JSONObject data = request.getJSONObject("data");
        JSONObject params = request.getJSONObject("params");
        String digest = request.getString("digest");
        String scenarioActionId = data.getString("scenarioActionId");
        QueryVo queryVo = new QueryVo();
        queryVo.filters.put("id", scenarioActionId);
        ProjectScenarioAction projectScenarioAction = projectScenarioActionService.retrieve(queryVo);
        String sfToken = projectScenarioAction.getSfToken();
        String selfDigest = getPayloadDigest(data, params, sfToken);
        if (!digest.equals(selfDigest)) {
            return AjaxResult.error("请求校验失败");
        }
        Integer deviceId = data.getInteger("deviceId");
        queryVo.filters.clear();
        queryVo.filters.put("id", deviceId);
        Device device = deviceService.retrieve(queryVo);
        String tbDeviceId = device.getTbDeviceId();
        JSONObject deltas = new JSONObject();
        String telemetryIdentifier = params.getString("telemetry");
        String incrementString = params.getString("increment");
        queryVo.filters.clear();
        queryVo.filters.put("product_id", device.getProductId());
        queryVo.filters.put("company_id", device.getCompanyId());
        List<ProductTelemetry> productTelemetries = productTelemetryService.index(queryVo);
        for (ProductTelemetry productTelemetry : productTelemetries) {
            if (productTelemetry.getUserIdentifier().equals(telemetryIdentifier)) {
                String dataTypeString = productTelemetry.getDataType();
                DataType dataType = DataType.valueOfLabel(dataTypeString);
                if (dataType.equals(DataType.BOOL) || dataType.equals(DataType.STRING)) {
                    return AjaxResult.error(String.format("遥测属性数据类型不支持增量操作：%s（%s）", dataType.getLabel(), dataType.getDescription()));
                }
                JSONObject delta = new JSONObject();
                delta.put("value", incrementString);
                delta.put("type", dataType);
                deltas.put(telemetryIdentifier, delta);
                break;
            }
        }
        if (deltas.isEmpty()) {
            return AjaxResult.error(String.format("请先添加产品 %s 的物模型遥测属性：%s", device.getProductName(), telemetryIdentifier));
        }
        SysCompanyThingsboard sysCompanyThingsboard = sysCompanyThingsboardService.selectSysCompanyThingsboardByCompanyId(projectScenarioAction.getCompanyId());
        JSONObject result = thingsBoardTenantService.addTelemetryDelta(tbDeviceId, deltas, sysCompanyThingsboard);
        if (result == null) {
            return AjaxResult.error("操作失败");
        }
        return AjaxResult.success(result);
    }

    @Override
    public AjaxResult deviceTelemetryIncrement(JSONObject request) {
        JSONObject data = request.getJSONObject("data");
        JSONObject params = request.getJSONObject("params");
        String digest = request.getString("digest");
        String scenarioActionId = data.getString("scenarioActionId");
        QueryVo queryVo = new QueryVo();
        queryVo.filters.put("id", scenarioActionId);
        ProjectScenarioAction projectScenarioAction = projectScenarioActionService.retrieve(queryVo);
        String sfToken = projectScenarioAction.getSfToken();
        String selfDigest = getPayloadDigest(data, params, sfToken);
        if (!digest.equals(selfDigest)) {
            return AjaxResult.error("请求校验失败");
        }
        Integer deviceId = params.getInteger("deviceId");
        queryVo.filters.clear();
        queryVo.filters.put("id", deviceId);
        Device device = deviceService.retrieve(queryVo);
        String tbDeviceId = device.getTbDeviceId();
        JSONObject deltas = new JSONObject();
        String telemetryIdentifier = params.getString("telemetry");
        String incrementString = params.getString("increment");
        queryVo.filters.clear();
        queryVo.filters.put("product_id", device.getProductId());
        queryVo.filters.put("company_id", device.getCompanyId());
        List<ProductTelemetry> productTelemetries = productTelemetryService.index(queryVo);
        for (ProductTelemetry productTelemetry : productTelemetries) {
            if (productTelemetry.getUserIdentifier().equals(telemetryIdentifier)) {
                String dataTypeString = productTelemetry.getDataType();
                DataType dataType = DataType.valueOfLabel(dataTypeString);
                if (dataType.equals(DataType.BOOL) || dataType.equals(DataType.STRING)) {
                    return AjaxResult.error(String.format("遥测属性数据类型不支持增量操作：%s（%s）", dataType.getLabel(), dataType.getDescription()));
                }
                JSONObject delta = new JSONObject();
                delta.put("value", incrementString);
                delta.put("type", dataType);
                deltas.put(telemetryIdentifier, delta);
                break;
            }
        }
        if (deltas.isEmpty()) {
            return AjaxResult.error(String.format("请先添加产品 %s 的物模型遥测属性：%s", device.getProductName(), telemetryIdentifier));
        }
        SysCompanyThingsboard sysCompanyThingsboard = sysCompanyThingsboardService.selectSysCompanyThingsboardByCompanyId(projectScenarioAction.getCompanyId());
        JSONObject result = thingsBoardTenantService.addTelemetryDelta(tbDeviceId, deltas, sysCompanyThingsboard);
        if (result == null) {
            return AjaxResult.error("操作失败");
        }
        return AjaxResult.success(result);
    }
}
